import { ErrorPayload, isErrorMessage, isErrorPayload, isMessage, isResponseMessage, isSendToMessage, isSendToPayload, isSendToRoomMessage, isSendToRoomPayload, Message, MessageType, ResponsePayload, SendToPayload, SendToRoomPayload } from "@core/types";
import { WebSocket } from "ws";
import { loadProto } from "./proto";
import { sendTo, sendToResponse, sendToRoom } from "./sendToResponse";

export async function handlerResponseFactory() {
    const rootProto = await loadProto()
    return async (result: ResponsePayload | ErrorPayload | SendToPayload | SendToRoomPayload, ws: WebSocket) => {
        let response = toMessage(result)
        if (isMessage(response)) {
            if (isResponseMessage(response)) {
                await sendToResponse(rootProto, response.payload)
            }
            else if (isErrorMessage(response)) {
                await sendToResponse(rootProto, response.payload)
            }
            else if (isSendToMessage(response)) {
                await sendTo(rootProto, response.payload)
            }
            else if (isSendToRoomMessage(response)) {
                await sendToRoom(rootProto, response.payload)
            }
            ws.send(JSON.stringify({ type: "RESPONSE_ACK", payload: { success: true, type: response.type } }))
        } else {
            ws.send(JSON.stringify({ type: "RESPONSE_ACK", payload: { success: false, type: 'unknown' } }))
        }
    }
}

function toMessage(data: ResponsePayload | ErrorPayload | SendToPayload | SendToRoomPayload) {
    if (isErrorPayload(data)) {
        return {
            type: MessageType.ERROR,
            payload: data
        } as Message<ErrorPayload>
    }
    else if (isSendToPayload(data)) {
        return {
            type: MessageType.SENDTO,
            payload: data
        } as Message<SendToPayload>
    }
    else if (isSendToRoomPayload(data)) {
        return {
            type: MessageType.SENDTOROOM,
            payload: data
        } as Message<SendToRoomPayload>
    } else {
        return {
            type: MessageType.RESPONSE,
            payload: data
        } as Message<ResponsePayload>
    }
}